/*
Copyright [2020] [https://www.stylefeng.cn]

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

  http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

Guns采用APACHE LICENSE 2.0开源协议，您在使用过程中，需要注意以下几点：

1.请不要删除和修改根目录下的LICENSE文件。
2.请不要删除和修改Guns源码头部的版权声明。
3.请保留源码和相关描述文件的项目出处，作者声明等。
4.分发源码时候，请注明软件出处 https://gitee.com/stylefeng/guns-separation
5.在修改包名，模块名称，项目代码等时，请注明软件出处 https://gitee.com/stylefeng/guns-separation
6.若您的项目无法满足以上几点，可申请商业授权，获取Guns商业授权许可，请在官网购买授权，地址为 https://www.stylefeng.cn
 */
package cn.stylefeng.guns.sys.modular.auth.service.impl;

import cn.hutool.captcha.generator.RandomGenerator;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUnit;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.spring.SpringUtil;
import cn.hutool.http.HttpResponse;
import cn.hutool.http.HttpUtil;
import cn.hutool.json.JSONUtil;
import cn.stylefeng.guns.core.consts.CommonConstant;
import cn.stylefeng.guns.core.context.constant.ConstantContextHolder;
import cn.stylefeng.guns.core.context.login.LoginContext;
import cn.stylefeng.guns.core.context.login.LoginContextHolder;
import cn.stylefeng.guns.core.dbs.CurrentDataSourceContext;
import cn.stylefeng.guns.core.enums.CommonStatusEnum;
import cn.stylefeng.guns.core.exception.AuthException;
import cn.stylefeng.guns.core.exception.ServiceException;
import cn.stylefeng.guns.core.exception.enums.AuthExceptionEnum;
import cn.stylefeng.guns.core.exception.enums.ServerExceptionEnum;
import cn.stylefeng.guns.core.pojo.login.SysLoginUser;
import cn.stylefeng.guns.core.pojo.response.ResponseData;
import cn.stylefeng.guns.core.tenant.context.TenantCodeHolder;
import cn.stylefeng.guns.core.tenant.context.TenantDbNameHolder;
import cn.stylefeng.guns.core.tenant.entity.TenantInfo;
import cn.stylefeng.guns.core.tenant.exception.TenantException;
import cn.stylefeng.guns.core.tenant.exception.enums.TenantExceptionEnum;
import cn.stylefeng.guns.core.tenant.service.TenantInfoService;
import cn.stylefeng.guns.core.util.HttpServletUtil;
import cn.stylefeng.guns.core.util.IpAddressUtil;
import cn.stylefeng.guns.sys.config.SsoServerConfigProperty;
import cn.stylefeng.guns.sys.config.SysExchangeConfigProperty;
import cn.stylefeng.guns.sys.config.SysSmtpConfigProperty;
import cn.stylefeng.guns.sys.core.cache.RedisBackCache;
import cn.stylefeng.guns.sys.core.cache.RedisCache;
import cn.stylefeng.guns.sys.core.cache.UserCache;
import cn.stylefeng.guns.sys.core.enums.AdminTypeEnum;
import cn.stylefeng.guns.sys.core.enums.LogSuccessStatusEnum;
import cn.stylefeng.guns.sys.core.jwt.JwtPayLoad;
import cn.stylefeng.guns.sys.core.jwt.JwtTokenUtil;
import cn.stylefeng.guns.sys.core.log.LogManager;
import cn.stylefeng.guns.sys.modular.auth.bean.SysRegisterBean;
import cn.stylefeng.guns.sys.modular.auth.constant.Constant;
import cn.stylefeng.guns.sys.modular.auth.factory.LoginUserFactory;
import cn.stylefeng.guns.sys.modular.auth.service.AuthService;
import cn.stylefeng.guns.sys.modular.file.util.DownloadUtil;
import cn.stylefeng.guns.sys.modular.role.entity.SysRole;
import cn.stylefeng.guns.sys.modular.role.service.SysRoleService;
import cn.stylefeng.guns.sys.modular.user.entity.SysUser;
import cn.stylefeng.guns.sys.modular.user.entity.SysUserCustom;
import cn.stylefeng.guns.sys.modular.user.entity.SysUserRole;
import cn.stylefeng.guns.sys.modular.user.mapper.SysUserCustomMapper;
import cn.stylefeng.guns.sys.modular.user.service.SysUserRoleService;
import cn.stylefeng.guns.sys.modular.user.service.SysUserService;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import io.jsonwebtoken.SignatureException;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import microsoft.exchange.webservices.data.core.ExchangeService;
import microsoft.exchange.webservices.data.core.service.item.EmailMessage;
import microsoft.exchange.webservices.data.credential.WebCredentials;
import microsoft.exchange.webservices.data.property.complex.MessageBody;
import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.bcrypt.BCrypt;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.crypto.Cipher;
import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
import java.io.File;
import java.math.BigInteger;
import java.net.URI;
import java.security.KeyFactory;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.interfaces.RSAPrivateKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * 认证相关service实现类
 *
 * @author xuyuxiang
 * @date 2020/3/11 16:58
 */
@Slf4j
@Service
public class AuthServiceImpl implements AuthService, UserDetailsService {

    private static final Logger LOGGER = org.apache.logging.log4j.LogManager.getLogger(AuthServiceImpl.class);

    private static final String REGISTER_TEXT = "【%s】您的注册验证码是：%s，5分钟内有效，请勿将验证码告知他人。";

    private static final String REGISTER_TEXT_EN = "[%s] Your registration verification code is: %s, valid for 5 minutes. Please do not disclose the verification code to others.";
//

//
//    private static final String EMAIL_PASSWORD = "ZQSLbjx258?aa";
//
//    private static final String EMAIL_URI = "https://mail.ieisystem.com/EWS/Exchange.asmx";
//
//    private static final String EMAIL_SMTPURI = "mail.ieisystem.com";
//
//    private static final String EMAIL_SMTPPORT = "587";

    @Resource
    private SysUserService sysUserService;

    @Resource
    private SysUserRoleService sysUserRoleService;

    @Resource
    private LoginContext loginContext;

    @Resource
    private SysRoleService sysRoleService;

    @Resource
    private UserCache userCache;

    @Autowired
    private RedisCache redisCache;

    @Autowired
    private RedisBackCache redisBackCache;

    @Autowired
    private SsoServerConfigProperty ssoServerConfigProperty;

//    @Autowired
//    private SimpleMailSender simpleMailSender;

    @Autowired
    private SysUserCustomMapper sysUserCustomMapper;

//    @Resource
//    private SysDictTypeService sysDictTypeService;
//
//    private final TimedCache<String, String> timedCache = CacheUtil.newTimedCache(10 * 1000L);

    @Autowired
    SysSmtpConfigProperty sysSmtpConfigProperty;

    @Autowired
    SysExchangeConfigProperty sysExchangeConfigProperty;

    @Override
    public String loginWithNoPwd(String account) {
        SysUser sysUser = sysUserService.getUserByCount(account);
        //用户不存在，账号或密码错误
        if (ObjectUtil.isEmpty(sysUser)) {
            LogManager.me().executeLoginLog(account, LogSuccessStatusEnum.FAIL.getCode(), AuthExceptionEnum.NO_LOGIN_USER.getMessage());
            throw new AuthException(AuthExceptionEnum.NO_LOGIN_USER);
        }
        return this.doLogin(sysUser);
    }

    @Override
    public String login(String account, String password, String locale) {
        if (ObjectUtil.hasEmpty(account, password)) {
            LogManager.me().executeLoginLog(account, LogSuccessStatusEnum.FAIL.getCode(), AuthExceptionEnum.ACCOUNT_PWD_EMPTY.getMessage());
            throw new AuthException(CommonConstant.ACCOUNT_PWD_EMPTY, locale);
        }
        try {
            // RAS2048解密
            account = new String(decrypt(Base64.getDecoder().decode(account), Constant.PRIVATE_KEY));
            password = new String(decrypt(Base64.getDecoder().decode(password), Constant.PRIVATE_KEY));
        } catch (Exception e) {
            e.printStackTrace();
            throw new AuthException(CommonConstant.DECRYPT_ERROR, locale);
        }

        SysUser sysUser = sysUserService.getUserByCount(account);
        // 用户不存在，账号或密码错误
        if (ObjectUtil.isEmpty(sysUser)) {
            // 此时登录的账号可能是邮箱，使用邮箱查询登录用户的信息
            List<SysUser> userList = sysUserService.getUserByEmail(account);
            if(CollectionUtil.isNotEmpty(userList)) {
                sysUser = userList.get(0);
                if(sysUser != null) {
                    account = sysUser.getAccount();
                } else {
                    LogManager.me().executeLoginLog(account, LogSuccessStatusEnum.FAIL.getCode(), AuthExceptionEnum.NO_LOGIN_USER.getMessage());
                    throw new AuthException(CommonConstant.ACCOUNT_PWD_ERROR, locale);
                }
            } else {
                LogManager.me().executeLoginLog(account, LogSuccessStatusEnum.FAIL.getCode(), AuthExceptionEnum.NO_LOGIN_USER.getMessage());
                throw new AuthException(CommonConstant.ACCOUNT_PWD_ERROR, locale);
            }
        }

        //判断用户是否被锁定
        if (redisCache.hasKey(CommonConstant.USER_LOCK_PREFIX + account) ) {
            LogManager.me().executeLoginLog(account, LogSuccessStatusEnum.FAIL.getCode(), AuthExceptionEnum.USER_LOCKED.getMessage());
            log.error("认证异常，用户---{}({})已被锁定，5分钟后解锁",account,sysUser.getName());
            throw new AuthException(CommonConstant.USER_LOCKED, locale);
        }

        String passwordBcrypt = sysUser.getPassword();
        // 客服对接,用户信息来源：01代表本地用户，02代表客服远程数据
        String sourceType = sysUser.getSourceType();
        if (CommonConstant.USER_SOURCE_TYPE_LOCALE.equals(sourceType)) {
            //验证账号密码是否正确
            if (ObjectUtil.isEmpty(passwordBcrypt) || !BCrypt.checkpw(password, passwordBcrypt)) {
                LogManager.me().executeLoginLog(sysUser.getAccount(), LogSuccessStatusEnum.FAIL.getCode(), AuthExceptionEnum.ACCOUNT_PWD_ERROR.getMessage());

                //判断用户是否到达锁定逻辑
                this.judgeUserLoginCount(sysUser);
                throw new AuthException(CommonConstant.ACCOUNT_PWD_ERROR, locale);
            }
        } else if (CommonConstant.USER_SOURCE_TYPE_REMOTE.equals(sourceType)) {
            String passwordMd5 = md5(password);
            if (StrUtil.isEmpty(passwordMd5) || StrUtil.isEmpty(passwordBcrypt) || !passwordBcrypt.equals(passwordMd5)) {
                LogManager.me().executeLoginLog(sysUser.getAccount(), LogSuccessStatusEnum.FAIL.getCode(), AuthExceptionEnum.ACCOUNT_PWD_ERROR.getMessage());

                //判断用户是否到达锁定逻辑
                this.judgeUserLoginCount(sysUser);
                throw new AuthException(CommonConstant.ACCOUNT_PWD_ERROR, locale);
            }
        }

        // 设置登录语言：中文/英文
        if(StrUtil.isBlank(locale)) {
            locale = "zh";
        }

        redisCache.put(sysUser.getAccount()+"_locale", locale);
        return this.doLogin(sysUser);
    }

    /**
     * 客服对接,客服系统加密方法
     */
    public static String md5(String s){
        try {
            s = s.toUpperCase().trim() + "yoopay";
            MessageDigest m = MessageDigest.getInstance("MD5");
            m.update(s.getBytes(), 0, s.length());
            s = new BigInteger(1, m.digest()).toString(16);
        } catch (NoSuchAlgorithmException ex) {
            log.error("Md5 加密错误---{}",ex.getMessage());
            ex.printStackTrace();
        }
        return s;
    }

    public byte[] decrypt(byte[] str, String privateKey) throws Exception {
        byte[] decoded = Base64.getDecoder().decode(privateKey);
        RSAPrivateKey priKey = (RSAPrivateKey) KeyFactory.getInstance("RSA").generatePrivate(new PKCS8EncodedKeySpec(decoded));
        Cipher cipher = Cipher.getInstance("RSA");
        cipher.init(2, priKey);
        return cipher.doFinal(str);
    }

    @Override
    public String getTokenFromRequest(HttpServletRequest request) {
        String authToken = request.getHeader(CommonConstant.AUTHORIZATION);
        if (ObjectUtil.isEmpty(authToken)) {
            return null;
        } else {
            //token不是以Bearer打头，则响应回格式不正确
            if (!authToken.startsWith(CommonConstant.TOKEN_TYPE_BEARER)) {
                throw new AuthException(AuthExceptionEnum.NOT_VALID_TOKEN_TYPE);
            }
            try {
                authToken = authToken.substring(CommonConstant.TOKEN_TYPE_BEARER.length() + 1);
            } catch (StringIndexOutOfBoundsException e) {
                throw new AuthException(AuthExceptionEnum.NOT_VALID_TOKEN_TYPE);
            }
        }

        return authToken;
    }

    @Override
    public SysLoginUser getLoginUserByToken(String token) {
        SysLoginUser sysLoginUser = null;
        Object cacheObject = null;
        JwtPayLoad jwtPayLoad = null;
        //校验token，错误则抛异常
        this.checkToken(token);

        //根据token获取JwtPayLoad部分
        try {
            jwtPayLoad = JwtTokenUtil.getJwtPayLoad(token);
            //从内存中获取登录用户
            cacheObject = userCache.get(jwtPayLoad.getUuid());
        } catch (SignatureException e) {
            LOGGER.error("getLoginUserByToken get userCache error: JWT signature does not match locally computed signature, JWT is invalid");
        }

        //用户不存在则表示登录已过期
        if (ObjectUtil.isEmpty(cacheObject)) {
            //从redis缓存中获取登录用户
            String json = redisCache.get(token);
            if(StrUtil.isNotEmpty(json)) {
                //转换成登录用户
                sysLoginUser = JSONUtil.toBean(json, SysLoginUser.class);
            } else {
                throw new AuthException(AuthExceptionEnum.LOGIN_EXPIRED);
            }
        } else {
            //转换成登录用户
            sysLoginUser = (SysLoginUser) cacheObject;
        }

        //用户存在, 无痛刷新缓存，在登录过期前活动的用户自动刷新缓存时间
        this.cacheLoginUser(jwtPayLoad, sysLoginUser, token);

        //返回用户
        return sysLoginUser;
    }

    @Override
    public void logout() {
        JwtPayLoad jwtPayLoad = null;
        HttpServletRequest request = HttpServletUtil.getRequest();
        if (ObjectUtil.isNotNull(request)) {
            //获取token
            String token = this.getTokenFromRequest(request);
            //如果token为空直接返回
            if (ObjectUtil.isEmpty(token)) {
                return;
            }

            try {
                //校验token，错误则抛异常，待确定
                this.checkToken(token);
                //根据token获取JwtPayLoad部分
                jwtPayLoad = JwtTokenUtil.getJwtPayLoad(token);
            } catch (Exception e) {
                LOGGER.error("logout Exception", e);
            }

            if(ObjectUtil.isNotEmpty(jwtPayLoad)) {
                //获取缓存的key
                String loginUserCacheKey = jwtPayLoad.getUuid();
                this.clearUser(loginUserCacheKey, jwtPayLoad.getAccount(), token);
            } else {
                this.clearUser(null, null, token);
            }
        } else {
            throw new ServiceException(ServerExceptionEnum.REQUEST_EMPTY);
        }
    }

    @Override
    public void setSpringSecurityContextAuthentication(SysLoginUser sysLoginUser) {
        UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken =
                new UsernamePasswordAuthenticationToken(
                        sysLoginUser,
                        null,
                        sysLoginUser.getAuthorities());
        SecurityContextHolder.getContext().setAuthentication(usernamePasswordAuthenticationToken);
    }

    @Override
    public Authentication getAuthentication() {
        return SecurityContextHolder.getContext().getAuthentication();
    }

    @Override
    public void checkToken(String token) {
        String json = null;
        //校验token是否正确
        Boolean tokenCorrect = JwtTokenUtil.checkToken(token);
        if (!tokenCorrect) {
            json = redisCache.get(token);
            if(StrUtil.isEmpty(json)) {
                throw new AuthException(AuthExceptionEnum.REQUEST_TOKEN_ERROR);
            }
        }

        if(StrUtil.isEmpty(json)) {
            //校验token是否失效
            Boolean tokenExpired = JwtTokenUtil.isTokenExpired(token);
            if (tokenExpired) {
                throw new AuthException(AuthExceptionEnum.LOGIN_EXPIRED);
            }
        }
    }

    @Override
    public void cacheTenantInfo(String tenantCode) {
        if (StrUtil.isBlank(tenantCode)) {
            return;
        }

        // 从spring容器中获取service，如果没开多租户功能，没引入相关包，这里会报错
        TenantInfoService tenantInfoService = null;
        try {
            tenantInfoService = SpringUtil.getBean(TenantInfoService.class);
        } catch (Exception e) {
            throw new TenantException(TenantExceptionEnum.TENANT_MODULE_NOT_ENABLE_ERROR);
        }

        // 获取租户信息
        TenantInfo tenantInfo = tenantInfoService.getByCode(tenantCode);
        if (tenantInfo != null) {
            String dbName = tenantInfo.getDbName();

            // 租户编码的临时存放
            TenantCodeHolder.put(tenantCode);

            // 租户的数据库名称临时缓存
            TenantDbNameHolder.put(dbName);

            // 数据源信息临时缓存
            CurrentDataSourceContext.setDataSourceType(dbName);
        } else {
            throw new TenantException(TenantExceptionEnum.CNAT_FIND_TENANT_ERROR);
        }
    }

    @Override
    public SysLoginUser loadUserByUsername(String account) throws UsernameNotFoundException {
        SysLoginUser sysLoginUser = new SysLoginUser();
        SysUser user = sysUserService.getUserByCount(account);
        BeanUtil.copyProperties(user, sysLoginUser);
        return sysLoginUser;
    }

    /**
     * 根据key清空登陆信息
     *
     * @author xuyuxiang
     * @date 2020/6/19 12:28
     */
    private void clearUser(String loginUserKey, String account, String token) {
        try {
            if(StrUtil.isNotEmpty(loginUserKey)) {
                //获取缓存的用户
                Object cacheObject = userCache.get(loginUserKey);
                //如果缓存的用户存在，清除会话，否则表示该会话信息已失效，不执行任何操作
                if (ObjectUtil.isNotEmpty(cacheObject)) {
                    //清除登录会话
                    userCache.remove(loginUserKey);
                    //创建退出登录日志
                    LogManager.me().executeExitLog(account);
                }
            }
        } catch (Exception e) {
            LOGGER.error("clearUser remove userCache error: " , e);
        }

        try{
            // 从redis中获取登录用户的信息
            String json = redisCache.get(token);
            if(StrUtil.isNotEmpty(json)) {
                redisCache.remove(token);
            }
            String tokenRedis = redisCache.get(loginUserKey);
            if(StrUtil.isNotEmpty(tokenRedis)){
                redisCache.remove(loginUserKey);
            }


            // 从备用redis中获取登录用户的信息
            String jsonBack = redisBackCache.get(token);
            if(StrUtil.isNotEmpty(jsonBack)) {
                redisBackCache.remove(token);
                redisBackCache.remove(loginUserKey);
            }
            String tokenRedisBack = redisCache.get(loginUserKey);
            if(StrUtil.isNotEmpty(tokenRedisBack)){
                redisCache.remove(loginUserKey);
            }
        } catch (Exception e) {
            LOGGER.error("clearUser remove redisCache error: " , e);
        }
    }

    /**
     * 执行登录方法
     *
     * @author xuyuxiang
     * @date 2020/3/12 10:43
     */
    private String doLogin(SysUser sysUser) {

        Integer sysUserStatus = sysUser.getStatus();

        //验证账号是否被冻结
        if (CommonStatusEnum.DISABLE.getCode().equals(sysUserStatus)) {
            LogManager.me().executeLoginLog(sysUser.getAccount(), LogSuccessStatusEnum.FAIL.getCode(), AuthExceptionEnum.ACCOUNT_FREEZE_ERROR.getMessage());
            throw new AuthException(AuthExceptionEnum.ACCOUNT_FREEZE_ERROR);
        }

        //构造SysLoginUser
        SysLoginUser sysLoginUser = this.genSysLoginUser(sysUser);

        //构造jwtPayLoad
        JwtPayLoad jwtPayLoad = new JwtPayLoad(sysUser.getId(), sysUser.getAccount());

        //生成token
        String token = JwtTokenUtil.generateToken(jwtPayLoad);

        //缓存token与登录用户信息对应, 默认2个小时
        this.cacheLoginUser(jwtPayLoad, sysLoginUser, token);

        //设置最后登录ip和时间
        sysUser.setLastLoginIp(IpAddressUtil.getIp(HttpServletUtil.getRequest()));
        sysUser.setLastLoginTime(DateTime.now());

        //更新用户登录信息
        sysUserService.updateById(sysUser);

        //登录成功，记录登录日志
        LogManager.me().executeLoginLog(sysUser.getAccount(), LogSuccessStatusEnum.SUCCESS.getCode(), null);

        //登录成功，设置SpringSecurityContext上下文，方便获取用户
        this.setSpringSecurityContextAuthentication(sysLoginUser);

        //登录成功重置失败标志位
        sysUserService.unLockUserClearLoginFailFlag(sysUser.getAccount());

        //如果开启限制单用户登陆，则踢掉原来的用户
        Boolean enableSingleLogin = ConstantContextHolder.getEnableSingleLogin();
        if (enableSingleLogin) {

            //获取所有的登陆用户
            Map<String, SysLoginUser> allLoginUsers = userCache.getAllKeyValues();
            for (Map.Entry<String, SysLoginUser> loginedUserEntry : allLoginUsers.entrySet()) {

                String loginedUserKey = loginedUserEntry.getKey();
                SysLoginUser loginedUser = loginedUserEntry.getValue();

                //如果账号名称相同，并且redis缓存key和刚刚生成的用户的uuid不一样，则清除以前登录的
                if (loginedUser.getName().equals(sysUser.getName())
                        && !loginedUserKey.equals(jwtPayLoad.getUuid())) {
                    String loginedToken = redisCache.get(loginedUserKey);
                    this.clearUser(loginedUserKey, loginedUser.getAccount(), loginedToken);
                }
            }
        }

        //返回token
        return token;
    }

    /**
     * 构造登录用户信息
     *
     * @author xuyuxiang
     * @date 2020/3/12 17:32
     */
    @Override
    public SysLoginUser genSysLoginUser(SysUser sysUser) {
        SysLoginUser sysLoginUser = new SysLoginUser();
        BeanUtil.copyProperties(sysUser, sysLoginUser);
        LoginUserFactory.fillLoginUserInfo(sysLoginUser);
        return sysLoginUser;
    }

    @Override
    public ResponseData checkUserLoginStatus(HttpServletRequest request) {
        // 1.如果当前请求带了token，判断token时效性，并获取当前登录用户信息
        SysLoginUser sysLoginUser = null;
        try {
            String token = this.getTokenFromRequest(request);
            if (StrUtil.isBlank(token)) {
                return ResponseData.error(302, "token为空");
            }
            sysLoginUser = this.getLoginUserByToken(token);
        } catch (AuthException ae) {
            //token过期或者token失效的情况，响应给前端
            return ResponseData.error(302, "用户登录状态已失效");
        }

        // 2.如果当前登录用户不为空，就设置spring security上下文
        this.setSpringSecurityContextAuthentication(sysLoginUser);
        return ResponseData.success(sysLoginUser);
    }

    @Override
    public ResponseData clientCheckTicket(String from, String account, String ticket) {
        Map<String, Object> param = MapUtil.<String, Object>builder()
                .put("from", from)
                .put("account", account)
                .put("ticket", ticket)
                .build();
        //请求sso 校验ticket票据正确性
        HttpResponse postResult = HttpUtil.createPost(this.buildTicketCheckUrl()).body(JSONUtil.toJsonStr(param)).execute();
        if (!postResult.isOk()) {
            log.error(">>>>> [{}] -> 票据验证异常, 票据信息: {}", from, ticket);
            return ResponseData.error(StrUtil.format("[{}]票据验证异常", from));
        }
        try {
            //ticket无误, 生成token
            String token = this.loginWithNoPwd(account);
            return ResponseData.success(token);
        } catch (Exception e) {
            log.error(">>>>> [{}] -> token生成异常, 异常信息: {}", from, e.getMessage());
            return ResponseData.error("[{}]token生成异常");
        }
    }

    /**
     * 构建请求
     */
    private String buildTicketCheckUrl() {
        return "http://" + ssoServerConfigProperty.getAddress() + ":" + ssoServerConfigProperty.getPort() + ssoServerConfigProperty.getTicketCheckUrl();
    }

    /**
     * 缓存token与登录用户信息对应, 默认2个小时
     *
     * @author xuyuxiang
     * @date 2020/3/13 14:51
     */
    private void cacheLoginUser(JwtPayLoad jwtPayLoad, SysLoginUser sysLoginUser, String token) {
        if (ObjectUtil.isNotEmpty(jwtPayLoad)) {
            String redisLoginUserKey = jwtPayLoad.getUuid();
            userCache.put(redisLoginUserKey, sysLoginUser);
        }

        if(StrUtil.isNotEmpty(token)) {
            // 在redis中缓存用户登录信息
            String json = JSONUtil.toJsonStr(sysLoginUser);
            redisCache.put(token, json, 3600*2L);
            redisBackCache.put(token, json, 3600*2);
            if (ObjectUtil.isNotEmpty(jwtPayLoad)) {
                // 放入redis用于强制下线
                String redisLoginUserKey = jwtPayLoad.getUuid();
                redisCache.put(redisLoginUserKey, token, 3600 * 2L);
                redisBackCache.put(redisLoginUserKey, json, 3600 * 2);
            }
        }
    }

    /**
     * 判断用户登录失败次数, 先获取失败次数若大于5次则将该用户锁定
     *
     * @param sysUser 用户
     * @return 结果 true 在范围内
     */
    private void judgeUserLoginCount(SysUser sysUser) {

        //不支持锁定超级管理员
        if (AdminTypeEnum.SUPER_ADMIN.getCode().equals(sysUser.getAdminType())) {
            return;
        }
        String account = sysUser.getAccount();

        // 客服对接
        int loginFailCount = 0;
        // 客服对接,登陆失败次数数据从redis里取
        if(redisCache.hasKey(CommonConstant.USER_LOGIN_FAIL_COUNT + account)){
            loginFailCount = Integer.parseInt(redisCache.get(CommonConstant.USER_LOGIN_FAIL_COUNT + account));
        }

        if (loginFailCount >= CommonConstant.MAX_LOGIN_FAILED_LOCK_COUNT -1) {

            //判断是否连续登录失败, 主要判断第一次登录时间与当前时间比较
            if (isInLoginFailTimeScope(sysUser)) {
                //符合锁定条件, 放入redis并设置失效时间, 并更新状态
                redisCache.put(CommonConstant.USER_LOCK_PREFIX + account, account, CommonConstant.USER_LOCKED_TIME);
                redisBackCache.put(CommonConstant.USER_LOCK_PREFIX + account, account, 5 * 60);

//                SysUserParam userParam = new SysUserParam();
//                userParam.setId(sysUser.getId());
//                userParam.setStatus(CommonStatusEnum.LOCKED.getCode());
//                sysUserService.changeStatus(userParam);


                log.info(">>> [{}] 用户符合锁定条件, 已被锁定!", account);
                throw new AuthException(AuthExceptionEnum.USER_LOCKED);

            } else {
                //清除登录失败标志信息
                sysUserService.unLockUserClearLoginFailFlag(account);
                log.info(">>> [{}] 用户不符合连续时间内登录失败次数条件, 已清除锁定标志!", account);
            }

        } else {

            if (loginFailCount == 0) {
                //第一次登录失败记录时间为后续连续判断准备
//                sysUserService.lambdaUpdate().eq(SysUser::getId, sysUser.getId())
//                        .set(SysUser::getFirstLoginFailTime, new Date())
//                        .update();

                redisCache.put(CommonConstant.USER_LOGIN_FIRST_FAIL_TIME + account, String.valueOf(new Date()), CommonConstant.LOGIN_FAILED_CYCLE);
                redisBackCache.put(CommonConstant.USER_LOGIN_FIRST_FAIL_TIME + account, String.valueOf(new Date()), (int) CommonConstant.LOGIN_FAILED_CYCLE);
            }

            //不合符锁定条件, 增加失败次数
//            sysUserService.userLoginFailCountIncrement(account);
            redisCache.put(CommonConstant.USER_LOGIN_FAIL_COUNT + account, String.valueOf(loginFailCount+1), CommonConstant.LOGIN_FAILED_CYCLE);
            redisBackCache.put(CommonConstant.USER_LOGIN_FAIL_COUNT + account, String.valueOf(loginFailCount+1), (int) CommonConstant.LOGIN_FAILED_CYCLE);

            log.info(">>> [{}] 用户未符合锁定条件, 登录失败次数: {} 次", account, loginFailCount + 1);
        }
    }


    /**
     * 判断用户登录失败时间在规定范围内
     *
     * @param sysUser 用户
     * @return 结果 true 在范围内
     */
    private boolean isInLoginFailTimeScope(SysUser sysUser) {
//        if (ObjectUtil.isNull(sysUser.getFirstLoginFailTime())) {
//            return false;
//        }
        String account = sysUser.getAccount();
        String lastLoginFailTimeStr = "";
        if(redisCache.hasKey(CommonConstant.USER_LOGIN_FIRST_FAIL_TIME + account)){
            lastLoginFailTimeStr = redisCache.get(CommonConstant.USER_LOGIN_FIRST_FAIL_TIME + account);
        }else if(StrUtil.isNotEmpty(redisBackCache.get(CommonConstant.USER_LOGIN_FIRST_FAIL_TIME + account)) ){
            lastLoginFailTimeStr = redisBackCache.get(CommonConstant.USER_LOGIN_FIRST_FAIL_TIME + account);
        }else{
            return false;
        }
        Date lastLoginFailTime = DateUtil.parse(lastLoginFailTimeStr);
        return DateUtil.between(lastLoginFailTime,DateUtil.date().toJdkDate(),DateUnit.SECOND)<= CommonConstant.LOGIN_FAILED_CYCLE;
    }


    /**
     *@description 同一个邮箱5分钟之内仅可以发送一次验证码
     *@author kongtao
     *@date  2023/12/15 14:59
     **/
    public boolean checkEmailLimit(String email) {
        try {
            if(StrUtil.isEmpty(email)) {
                return true;
            }

            SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
            String dateStr = sdf.format(new Date());
            String key = email + "_" + dateStr;
            key = key.toLowerCase();
            if(redisCache.hasKey(key)) {
                LOGGER.info("***********email*******key: " + key);
                return false;
            }

            redisCache.put(key, key, 300L);
        } catch (Exception e) {
            LOGGER.error("AuthServiceImpl checkEmailLimit error: ", e);
        }

        return true;
    }

    /**
     *@description 同一个IP 1分钟内连续发送请求超过5次则锁定1分钟
     *@author kongtao
     *@date  2023/12/15 16:20
     **/
    public boolean checkCountLimit(String salt) {
        try {
            String ip = null;
            HttpServletRequest request = HttpServletUtil.getRequest();
            if (ObjectUtil.isNotNull(request)) {
                ip = IpAddressUtil.getIp(request);
            }

            if(StrUtil.isEmpty(ip)) {
                return true;
            }

            SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss");
            String dateStr = sdf.format(new Date());
            String key = ip + "_" + salt + "_" + dateStr;
            Collection<String> values = redisCache.getAllValues();
            String val = redisCache.get(ip + "_locked" + "_" + salt);
            if(StrUtil.isNotEmpty(val)) {
                return false;
            }

            int count = 0;
            for(String value : values) {
                if(value.contains(ip + "_" + salt)) {
                    count ++;
                }
            }

            if(count > 4) {
                key = ip + "_locked" + "_" + salt;
                redisCache.put(key, key, 300L);
                return false;
            }

            redisCache.put(key, key, 300L);
        } catch (Exception e) {
            LOGGER.error("AuthServiceImpl checkIpCodeLimit error: ", e);
        }

        return true;
    }

    /**
     *@description 同一个IP 5分钟内连续发送验证码超过5次则锁定5分钟
     *@author kongtao
     *@date  2023/12/15 16:20
     **/
    public boolean checkIpLimit(String salt) {
        try {
            String ip = null;
            HttpServletRequest request = HttpServletUtil.getRequest();
            if (ObjectUtil.isNotNull(request)) {
                ip = IpAddressUtil.getIp(request);
            }

            if(StrUtil.isEmpty(ip)) {
                return true;
            }

            SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss");
            String dateStr = sdf.format(new Date());
            String key = ip + "_" + salt + "_" + dateStr;
            Collection<String> values = redisCache.getAllValues();
            String val = redisCache.get(ip + "_locked" + "_" + salt);
            if(StrUtil.isNotEmpty(val)) {
                return false;
            }

            int count = 0;
            for(String value : values) {
                if(value.contains(ip + "_" + salt)) {
                    count ++;
                }
            }

            if(count > 5) {
                key = ip + "_locked" + "_" + salt;
                redisCache.put(key, key, 300L);
                return false;
            }

            redisCache.put(key, key, 300L);
        } catch (Exception e) {
            LOGGER.error("AuthServiceImpl checkIpCodeLimit error: ", e);
        }

        return true;
    }

    @Override
    public ResponseData<?> sendRegisterEmail(String account, String email, String locale) {
        // 20240115 不需要验证序列号也可以注册
        if (StringUtils.isBlank(account) || StringUtils.isBlank(email)) {
            if(StrUtil.isNotBlank(locale) && "en".equals(locale)) {
                return ResponseData.error("Account, email are empty");
            } else {
                return ResponseData.error("账号、邮箱为空");
            }
        }

        // RAS2048解密
        try {
            account = new String(decrypt(Base64.getDecoder().decode(account), Constant.PRIVATE_KEY));
        } catch (Exception e) {
            LOGGER.error("账号解密异常, {}", e.getMessage());
            if(StrUtil.isNotBlank(locale) && "en".equals(locale)) {
                return ResponseData.error("Account abnormality");
            } else {
                return ResponseData.error("账号异常");
            }
        }

        if (Objects.nonNull(sysUserService.getUserByCount(account))) {
            if(StrUtil.isNotBlank(locale) && "en".equals(locale)) {
                return ResponseData.error("Account registered, no need for duplicate registration");
            } else {
                return ResponseData.error("账号已注册，无需重复注册");
            }
        }

        if (CollUtil.isNotEmpty(sysUserService.getUserByEmail(email))) {
            if(StrUtil.isNotBlank(locale) && "en".equals(locale)) {
                return ResponseData.error("Account registered, no need for duplicate registration");
            } else {
                return ResponseData.error("邮箱已注册，无需重复注册");
            }
        }

        if(!checkEmailLimit(email)) {
            if(StrUtil.isNotBlank(locale) && "en".equals(locale)) {
                return ResponseData.error("The same email can only send a verification code once within 5 minutes");
            } else {
                return ResponseData.error("同一邮箱在5分钟内仅可以发送一次验证码");
            }
        }

        if(!checkIpLimit("code")) {
            if(StrUtil.isNotBlank(locale) && "en".equals(locale)) {
                return ResponseData.error("The operation is too frequent, please try again in 5 minutes");
            } else {
                return ResponseData.error("操作太频繁，请5分钟之后再尝试");
            }
        }

        RandomGenerator randomGenerator = new RandomGenerator("0123456789", 6);
        String code = randomGenerator.generate();
        // redis记录
        String key = String.join("_", CommonConstant.REGISTER_CODE, account, email);
        redisCache.put(key, code, CommonConstant.REGISTER_CODE_EXP_TIME);
        redisBackCache.put(key, code, 5 * 60);

        // 发送验证码邮件
        if(StrUtil.isNotBlank(locale) && "en".equals(locale)) {
            // 先使用smtp方式发送，不行再用exchange
            if(!sendSmtpEmail(email,null,"Registration verification code",REGISTER_TEXT_EN.formatted(sysSmtpConfigProperty.getAppName(),code))){
                if (!sendEmail("Registration verification code", REGISTER_TEXT_EN.formatted(code), email, null)) {
                    return ResponseData.error("Email service exception, verification code sending failed. Please contact the administrator");
                }
            }

        } else {
            // 先使用smtp方式发送，不行再用exchange
            if(!sendSmtpEmail(email,null,"注册验证码",REGISTER_TEXT.formatted(sysSmtpConfigProperty.getAppName(),code))){
                if (!sendEmail("注册验证码", REGISTER_TEXT.formatted(code), email, null)) {
                    return ResponseData.error("邮箱服务异常，验证码发送失败，请联系管理员");
                }
            }
        }

        return ResponseData.success();
    }

    @Transactional
    @Override
    public ResponseData<?> doRegister(SysRegisterBean registerBean) {
        if(!checkIpLimit("register")) {
            if(registerBean != null && "en".equals(registerBean.getLocale())) {
                return ResponseData.error("The operation is too frequent, please try again in 5 minutes");
            } else {
                return ResponseData.error("操作太频繁，请5分钟之后再尝试");
            }
        }

        if (Objects.isNull(registerBean) || StringUtils.isAnyBlank(registerBean.getAccount(), registerBean.getPassword(), registerBean.getEmail(), registerBean.getVerificationCode())) {
            if(registerBean != null && "en".equals(registerBean.getLocale())) {
                return ResponseData.error("Registration information cannot be empty");
            } else {
                return ResponseData.error("注册信息不可为空");
            }
        }

        // RAS2048解密
        String account = null;
        String password = null;
        try {
            account = new String(decrypt(Base64.getDecoder().decode(registerBean.getAccount()), Constant.PRIVATE_KEY));
            password = new String(decrypt(Base64.getDecoder().decode(registerBean.getPassword()), Constant.PRIVATE_KEY));
        } catch (Exception e) {
            LOGGER.error("账号、密码解密异常,{}", e.getMessage());
            if(registerBean != null && "en".equals(registerBean.getLocale())) {
                return ResponseData.error("Account and password abnormalities");
            } else {
                return ResponseData.error("账号、密码异常");
            }
        }

        String email = registerBean.getEmail();
        // 校验验证码
        String key = String.join("_", CommonConstant.REGISTER_CODE, account, email);
        String codeBack = redisBackCache.get(key);
        LOGGER.info("**************codeBack:" + codeBack);
        String code = redisCache.hasKey(key) ? redisCache.get(key) : StringUtils.isNotBlank(codeBack) ? codeBack : null;
        LOGGER.info("**************code:" + code);
        LOGGER.info("**************registerBean.getVerificationCode():" + registerBean.getVerificationCode());
        if (!StringUtils.equals(code, registerBean.getVerificationCode())) {
            if(registerBean != null && "en".equals(registerBean.getLocale())) {
                return ResponseData.error("Verification code error");
            } else {
                return ResponseData.error("验证码错误");
            }
        }

        if (Objects.nonNull(sysUserService.getUserByCount(account))){
            if(registerBean != null && "en".equals(registerBean.getLocale())) {
                return ResponseData.error("Account or email registered");
            } else {
                return ResponseData.error("账号已注册");
            }
        }

        if (CollUtil.isNotEmpty(sysUserService.getUserByEmail(email))) {
            if(registerBean != null && "en".equals(registerBean.getLocale())) {
                return ResponseData.error("Account or email registered");
            } else {
                return ResponseData.error("邮箱已注册");
            }
        }

        // 移除缓存
        redisCache.remove(key);
        redisBackCache.remove(key);

        /*String cert = CertAuthUtil.generateCert(account, password);
        if (StringUtils.isBlank(cert)) {
            if(registerBean != null && "en".equals(registerBean.getLocale())) {
                return ResponseData.error("Certificate generation exception, failed to add user");
            } else {
                return ResponseData.error("证书生成异常，新增用户失败");
            }
        }*/

        // 新增用户
        SysUser newUser = new SysUser();
        newUser.setAccount(account);
        newUser.setEmail(email);
        newUser.setPassword(BCrypt.hashpw(password, BCrypt.gensalt()));
        newUser.setAdminType(2);
        // 注册时最后一次修改密码时间设置为当前时间，避免登录后弹出修改密码弹框
        newUser.setLastUpdPwdTime(new Date());
        // newUser.setCertificatePath(cert);
        // 必填项
        newUser.setSex(3);
        newUser.setName(account);
        newUser.setIndustry(registerBean.getIndustry());
        if (!sysUserService.save(newUser)) {
            if(registerBean != null && "en".equals(registerBean.getLocale())) {
                return ResponseData.error("Failed to add user");
            } else {
                return ResponseData.error("新增用户失败");
            }
        }

        // 查询角色信息
        SysUser newCount = sysUserService.getUserByCount(account);
        addRoleByCode(registerBean, "outside_cust", newCount);

        // 判断用户邮箱如果是@inspur.com邮箱，增加角色Inspur邮箱外部注册，可以下载IMSCLI
        if(StrUtil.isNotEmpty(email) && email.endsWith("@inspur.com")){
            addRoleByCode(registerBean, "inspur_email_outside_cust", newCount);
        }

        // 判断用户邮箱如果是@ieisystem.com邮箱，增加角色普通用户，都能看
        if(StrUtil.isNotEmpty(email) &&  email.endsWith("@ieisystem.com") ){
            addRoleByCode(registerBean, "ptyh", newCount);
        }

        // 2024-1-15 序列号不验证也可注册
        SysUserCustom entity = new SysUserCustom();
        // 2024-02-06 如果注册邮箱为浪潮的邮箱，不管是否验证了序列号，不限制查询
        if(StrUtil.isNotEmpty(email) && ( email.endsWith("@inspur.com") || email.endsWith("@ieisystem.com") )){
            entity.setCustomId(1L);
            entity.setUserId(newCount.getId());
            entity.setCreateTime(new Date());
            sysUserCustomMapper.insert(entity);
        }else{
            // 非浪潮邮箱
            String snOk = registerBean.getSnOk();
            if("true".equals(snOk)){
                // 已验证过序列号，此表插入记录（注册时如果使用sn为通用机器，则插入一条CustomId为1的记录）
                if (Objects.nonNull(registerBean.getCustomId())) {
                    entity.setCustomId(registerBean.getCustomId());
                }else{
                    entity.setCustomId(1L);
                }
                entity.setUserId(newCount.getId());
                entity.setCreateTime(new Date());
                sysUserCustomMapper.insert(entity);
            }// else 验证序列号没通过或未验证序列号，不插入数据
        }

        // 发送证书
        /*if(registerBean != null && "en".equals(registerBean.getLocale())) {
            if (!sendEmail("digital certificate", CERTIFICATE_TEXT_EN.formatted(account), email, cert)) {
                LOGGER.error("邮箱服务异常，数字证书发送失败");
            }
        } else {
            if (!sendEmail("数字证书", CERTIFICATE_TEXT.formatted(account), email, cert)) {
                LOGGER.error("邮箱服务异常，数字证书发送失败");
            }
        }*/

        return ResponseData.success();
    }

    private void addRoleByCode(SysRegisterBean registerBean, String roleCode, SysUser newCount) {
        LambdaQueryWrapper<SysRole> querySysRole = new LambdaQueryWrapper<>();
        querySysRole.eq(SysRole::getCode, roleCode).eq(SysRole::getStatus, 0);
        SysRole sysRole = sysRoleService.getOne(querySysRole);
        if (Objects.isNull(sysRole) || Objects.isNull(sysRole.getId())) {
            if(registerBean != null && "en".equals(registerBean.getLocale())) {
                LOGGER.error("Role information is empty, adding new user failed------"+ roleCode);
            } else {
                LOGGER.error("角色信息为空，新增用户失败------"+ roleCode);
            }
        }else{
            // 新增用户角色关系
            SysUserRole sysUserRole = new SysUserRole();
            sysUserRole.setUserId(newCount.getId());
            sysUserRole.setRoleId(sysRole.getId());
            sysUserRoleService.save(sysUserRole);
        }
    }

    @Override
    public ResponseData<?> bindSn(SysRegisterBean registerBean) {
        try {
            Long sysLoginUserId = LoginContextHolder.me().getSysLoginUserId();
            SysUser sysUser = sysUserService.getUserByUserId(sysLoginUserId);
            SysUserCustom entity = new SysUserCustom();
            String snOk = registerBean.getSnOk();
            // 2024-02-06 如果注册邮箱为浪潮的邮箱，不管是否验证了序列号，不限制查询
            String email = sysUser.getEmail();
            if(StrUtil.isNotEmpty(email) && ( email.endsWith("@inspur.com") || email.endsWith("@ieisystem.com") )) {
                entity.setCustomId(1L);
                entity.setUserId(sysLoginUserId);
                entity.setCreateTime(new Date());
                sysUserCustomMapper.insert(entity);
                return ResponseData.success();
            }else{
                if("true".equals(snOk)){
                    // 已验证过序列号，此表插入记录（如果使用sn为通用机器，则插入一条CustomId为1的记录）
                    if (Objects.nonNull(registerBean.getCustomId())) {
                        entity.setCustomId(registerBean.getCustomId());
                    }else{
                        entity.setCustomId(1L);
                    }
                    entity.setUserId(sysLoginUserId);
                    entity.setCreateTime(new Date());
                    sysUserCustomMapper.insert(entity);
                    return ResponseData.success();
                }else{
                    // 验证序列号没通过或未验证序列号，不插入数据
                    if(registerBean != null && "en".equals(registerBean.getLocale())) {
                        return ResponseData.error("Unverified serial number");
                    } else {
                        return ResponseData.error("未验证序列号");
                    }
                }
            }
        }catch (Exception e){
            if(registerBean != null && "en".equals(registerBean.getLocale())) {
                return ResponseData.error("Binding serial number failed"+e.getMessage());
            } else {
                return ResponseData.error("绑定序列号失败"+e.getMessage());
            }
        }
    }

    /**
     * smtp方式发送邮件
     * @param email
     * @param ccEmail
     * @param subject
     * @param message
     * @return
     */
    public boolean sendSmtpEmail(String email, String ccEmail, String subject, String message) {
        List<String> toAddresses = new ArrayList<>();
        if(StrUtil.isNotBlank(email)){
            toAddresses.add(email);
        }
        List<String> ccAddresses = new ArrayList<>();
        if(StrUtil.isNotBlank(ccEmail)){
            Arrays.asList(ccEmail);
            ccAddresses.add(ccEmail);
        }
        try {
//            String userName = "", password = "",smtpUri = "",smtpPort = "";
//            SysDictTypeParam sysDictTypeParam = new SysDictTypeParam();
//            // 典型规则
//            sysDictTypeParam.setCode("register_mail");
//            List<Dict> typicalRuleList = sysDictTypeService.dropDown(sysDictTypeParam);
//            if(CollectionUtil.isNotEmpty(typicalRuleList)) {
//                for(Dict dict : typicalRuleList) {
//                    Object keyObject = dict.get("code");
//                    Object valueObject = dict.get("value");
//                    if(keyObject != null && "userName".equals(keyObject.toString()) && valueObject != null) {
//                        userName = valueObject.toString();
//                    } else if(keyObject != null && "password".equals(keyObject.toString()) && valueObject != null) {
//                        password = valueObject.toString();
//                    }  else if(keyObject != null && "smtpUri".equals(keyObject.toString()) && valueObject != null) {
//                        smtpUri = valueObject.toString();
//                    }  else if(keyObject != null && "smtpPort".equals(keyObject.toString()) && valueObject != null) {
//                        smtpPort = valueObject.toString();
//                    }
//                }
//            } else {
//                LOGGER.error("未从字典中查询到SMTP服务邮箱的配置信息");
//                return false;
//            }
//
//            if(StrUtil.isEmpty(userName) || StrUtil.isEmpty(password)|| StrUtil.isEmpty(smtpUri)|| StrUtil.isEmpty(smtpPort)) {
//                LOGGER.error("SMTP服务邮箱的配置信息不完整");
//                return false;
//            }
            log.info("配置邮箱信息------"+sysSmtpConfigProperty.toString());
            // 设置邮件服务器属性
            Properties props = new Properties();
            String appName = sysSmtpConfigProperty.getAppName();
            if(!"KsManage Repo".equals(appName)){
                props.put("mail.smtp.auth", sysSmtpConfigProperty.getAuth());
            }
            props.put("mail.smtp.host", sysSmtpConfigProperty.getHost());
            props.put("mail.smtp.port", sysSmtpConfigProperty.getPort());
            // 创建会话对象
            Session session = Session.getInstance(props);
            try {
                // 创建邮件消息对象
                MimeMessage msg = new MimeMessage(session);
                msg.setFrom(new InternetAddress(sysSmtpConfigProperty.getFrom()));
                //添加发件人
                for (String toAddress : toAddresses) {
                    msg.addRecipient(Message.RecipientType.TO, new InternetAddress(toAddress));
                }

                // 添加抄送地址
                for (String ccAddress : ccAddresses) {
                    msg.addRecipient(Message.RecipientType.CC, new InternetAddress(ccAddress));
                }

                msg.setSubject(subject);
                // 设置内容和格式
                msg.setText(message);
                msg.setContent(message, "text/html; charset=utf-8");
                LOGGER.info("SMTP邮箱服务---收件人：{},抄送：{},主题：{},内容:{}", email,ccEmail,subject,message);
                // 发送邮件
                Transport transport = session.getTransport("smtp");
                if("KsManage Repo".equals(appName)){
                    transport.connect();
                }else{
                    transport.connect(sysSmtpConfigProperty.getHost(), sysSmtpConfigProperty.getUsername(), sysSmtpConfigProperty.getPassword());
                }
                transport.sendMessage(msg, msg.getAllRecipients());
                LOGGER.info("SMTP邮箱服务邮件发送成功");
                return true;
            } catch (MessagingException e) {
                LOGGER.error("SMTP邮箱服务异常，邮件发送失败，{}", e.getMessage());
                return false;
            } finally {
                session = null;
            }
        } catch (Exception e) {
            LOGGER.error("SMTP邮箱准备服务异常，邮件发送失败，{}", e.getMessage());
            return false;
        }
    }
    public boolean sendEmail(String subject, String body, String recipient, String attachment) {
        try {
//            String userName = "", password = "", uri = "", domain = "";
//            SysDictTypeParam sysDictTypeParam = new SysDictTypeParam();
//            // 典型规则
//            sysDictTypeParam.setCode("register_mail");
//            List<Dict> typicalRuleList = sysDictTypeService.dropDown(sysDictTypeParam);
//            if(typicalRuleList != null && typicalRuleList.size() > 0) {
//                for(Dict dict : typicalRuleList) {
//                    Object keyObject = dict.get("code");
//                    Object valueObject = dict.get("value");
//                    if(keyObject != null && "userName".equals(keyObject.toString()) && valueObject != null) {
//                        userName = valueObject.toString();
//                    } else if(keyObject != null && "password".equals(keyObject.toString()) && valueObject != null) {
//                        password = valueObject.toString();
//                    } else if(keyObject != null && "uri".equals(keyObject.toString()) && valueObject != null) {
//                        uri = valueObject.toString();
//                    }  else if(keyObject != null && "domain".equals(keyObject.toString()) && valueObject != null) {
//                        domain = valueObject.toString();
//                    }
//                }
//            } else {
//                LOGGER.error("未从字典中查询到服务邮箱的账号和密码");
//            }
//
//            if(StrUtil.isEmpty(userName) || StrUtil.isEmpty(password)) {
//                return false;
//            }

            WebCredentials credentials = new WebCredentials(sysExchangeConfigProperty.getUsername(), sysExchangeConfigProperty.getPassword(), "");
            ExchangeService exchangeService = new ExchangeService();
            exchangeService.setUrl(new URI(sysExchangeConfigProperty.getHost()));
            exchangeService.setCredentials(credentials);
            EmailMessage message = new EmailMessage(exchangeService);
            // 主题
            message.setSubject(subject);
            LOGGER.info("邮件主题:" + subject);
            // 内容
            message.setBody(MessageBody.getMessageBodyFromText(body));
            LOGGER.info("邮件内容:" + body);
            // 收件人
            message.getToRecipients().add(recipient);
            LOGGER.info("收件人邮箱:" + recipient);
            // 附件
            if (StringUtils.isNotBlank(attachment)) {
                message.getAttachments().addFileAttachment(attachment);
            }

            message.send();
            return true;
        } catch (Exception e) {
            LOGGER.error("邮箱服务异常，邮件发送失败，{}", e.getMessage());
            return false;
        }
    }

    @Override
    public void downloadCertificate(HttpServletResponse response) {
        SysLoginUser loginUser = loginContext.getSysLoginUser();
        if (Objects.isNull(loginUser) || StringUtils.isBlank(loginUser.getAccount())) {
            LOGGER.error("查询当前登录用户失败");
            throw new RuntimeException("查询当前登录用户失败");
        }
        SysUser currentUser = sysUserService.getUserByCount(loginUser.getAccount());
        if (Objects.isNull(currentUser) || StringUtils.isBlank(currentUser.getCertificatePath())) {
            LOGGER.error("查询用户证书信息失败");
            throw new RuntimeException("查询用户证书信息失败");
        }
        DownloadUtil.download(new File(currentUser.getCertificatePath()), response);
    }
}
